Skip to main content

4.1 - Static Info - Map Name, Size, and Start Locations

Before a single unit moves, your bot needs a complete understanding of the environment. The self.game_info object is your access to this static blueprint. Think of it as the unchangeable physical game board: the map's size, terrain, and starting positions are all fixed at the beginning of the match and will not change.

This information is your foundation for all high-level strategy. It's available from on_start() onwards and is essential for planning expansions, identifying chokepoints, and, most importantly, finding your enemy.

The Most Important Data: Start Locations

Locating the enemy is your first priority. The library provides several properties to help, and it's critical to understand the difference.

      THE MAP (e.g., Acropolis LE)
+------------------------------------+
| P1 o | P1: Your bot's actual start
|(self.start_location) |
| |
| |
| |
| |
| o P3 | 2: The enemy's actual start
| (self.enemy_start_locations[0])|
+------------------------------------+
PropertyWhat It IsCommon Use
self.start_locationYour exact starting Point2.Finding the center of your own base.
self.enemy_start_locationsA list of your opponents' exact starting locations.The primary way you find the enemy in a 1v1.

The self.game_info Attribute Table

This table details the core components of the battlefield blueprint and their strategic value.

AttributeData TypeDescription & Practical Use Case
map_namestrThe name of the map file (e.g., "AbyssalReefLE").
Use: Log which maps your bot wins or loses on.
map_sizeSizeDimensions (.width, .height) of the map.
Use: Judge travel times and estimate the size of your army.
playable_areaRectA rectangle defining the map's playable boundaries.
Use: Keep your units from getting stuck on unplayable edges.
pathing_gridPixelMapA 2D array showing walkable terrain for ground units.
Use (Advanced): Find chokepoints or wall-off locations by analyzing pathable tiles.
placement_gridPixelMapA 2D array showing where buildings can be constructed.
Use (Advanced): Find optimal, non-blocking spots for buildings.
For RL DevelopersN/AThis static data is perfect for an RL agent's observation space, as it only needs to be processed once, reducing the complexity of per-frame observations.

Practical Application Checklist

Here is how you should think about using self.game_info in your own projects:

  • 1. Find the Enemy: Immediately grab self.enemy_start_locations[0] to get your primary target.
  • 2. Plan Expansions: Find the closest base location in self.expansion_locations_list (a helper property) to your self.start_location or use self.get_next_expansion() that finds the closest, unoccupied expansion location to your existing bases.
  • 3. Determine Build Patterns: Use your start location to decide on safe places to build, like placing a Supply Depot behind your mineral line.
  • 4. Set Rally Points: Calculate a safe rally point between your base and the enemy's for newly trained units.

Code Example: The Strategist Bot

This bot uses self.game_info in on_start to make several strategic decisions at the very beginning of the game.

# strategist_bot.py

from sc2.main import run_game
from sc2 import maps
from sc2.bot_ai import BotAI
from sc2.ids.unit_typeid import UnitTypeId
from sc2.player import Bot, Computer
from sc2.data import Difficulty, Race


class StrategistBot(BotAI):
"""A bot that uses static info to make initial strategic decisions."""

async def on_start(self):
"""Analyze the blueprint and set up a basic plan."""
print("--- Battlefield Blueprint Analysis ---")

# 1. Find the enemy's main base. This is our primary target.
self.enemy_main_base = self.enemy_start_locations[0]
print(f"Enemy main located at: {self.enemy_main_base.rounded}")

# 2. Find a safe position behind our mineral line to build depots.
# This uses vector math to move from our townhall away from the main ramp.
self.safe_build_position = self.start_location.towards(
self.main_base_ramp.top_center, -8
)
print(f"Designated safe building position: {self.safe_build_position.rounded}")

# 3. Designate a scout. We'll tag one worker for this role.
# Note: We store the tag, not the unit object, as the object can become stale.
self.scout_tag = self.workers.random.tag
print(f"Worker {self.scout_tag} has been assigned scouting duty.")
print("--- Analysis Complete ---")

async def on_step(self, iteration: int):
"""Execute the plan set in on_start."""
# Action 1: Send the designated scout to the enemy base on the first step.
if iteration == 0:
scout_unit = self.workers.by_tag(self.scout_tag)
if scout_unit:
scout_unit.attack(self.enemy_main_base)
print(f"ACTION: Scout {self.scout_tag} dispatched to enemy base.")

# Action 2: Build a Supply Depot when we are close to our supply cap.
# We also check if we can afford it and are not already building one.
if (
self.supply_left < 5
and self.can_afford(UnitTypeId.SUPPLYDEPOT)
and self.already_pending(UnitTypeId.SUPPLYDEPOT) == 0
):
# self.build is async, so it must be awaited.
await self.build(UnitTypeId.SUPPLYDEPOT, near=self.safe_build_position)
print(
f"ACTION: Building Supply Depot at safe location {self.safe_build_position.rounded}."
)


if __name__ == "__main__":
run_game(
maps.get("AbyssalReefLE"),
[Bot(Race.Terran, StrategistBot()), Computer(Race.Zerg, Difficulty.Easy)],
realtime=True,
)

Interactive Map Demonstration